package opt_str

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"math"
	"math/rand"
	"net"
	"net/url"
	"os"
	"runtime"
	"time"
)

func Traver_sal_string() {
	// 默认 byte类型
	s := "pprof.cn博客"
	for i := 0; i < len(s); i++ { //byte
		fmt.Printf("%v(%c) ", s[i], s[i])
	}
	fmt.Println()
	// UTF-8 类型
	for _, r := range s { //rune
		fmt.Printf("%v(%c) ", r, r)
	}
	fmt.Println()
}

// 修改字符
func Update_str() {
	var str_byte = "你好 goland ！"
	run_str := []rune(str_byte)

	run_str[2] = '不'
	fmt.Println(string(run_str))
}

func FloatTransDouble() {
	var f1 = 2
	var i int

	i = int(math.Pow10(f1))

	fmt.Println("float i is ", i)
}

func Array_opt() {
	var arr = [4]int{2, 4, 5}

	var arr_bool = [3]bool{true, false}

	var arr_1 = [...]int{2, 3, 6, 7}

	fmt.Println(arr, arr_1, arr_bool)
}

// 按值传递
func SumArr(a [10]int) {
	var sum int = 0
	for i, n := range a {
		fmt.Println(n, "====", i)
		sum += i
	}

	println("sum is ", sum)
}

func Generate_rand() {
	rand.Seed(time.Now().Unix())
	var index = 10
	var arr = [10]int{}
	// index out of range
	// var arr = []int{}
	for i := 0; i < index; i++ {
		// index out of range
		arr[i] = rand.Intn(1000)
	}

	fmt.Println("arr is ", arr)
}

func Slice_Arr() {
	// 切片声明
	var s1 []int
	var s2 = []int{}
	var s3 = make([]int, 2)
	var s4 = make([]int, 0, 0)

	if s1 == nil {
		fmt.Println("s1 is null")
	} else {
		fmt.Println("s1 is not null")
	}

	if s2 == nil {
		fmt.Println("s1 is null")
	} else {
		fmt.Println("s1 is not null")
	}

	if s3 == nil {
		fmt.Println("s is null")
	} else {
		fmt.Println("s1 is not null")
	}
	if s4 == nil {
		fmt.Println("s1 is null")
	} else {
		fmt.Println("s1 is not null")
	}

}

func Init_Slice() {
	var s1 []int
	if s1 != nil {
		fmt.Println("s1 is not  null")
	} else {
		fmt.Println("s1 is 1 null")
	}

	var s2 = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	s3 := s2[:]

	fmt.Println("s3 is ", s3)

	s4 := s2[0:]
	s5 := s2[1:]

	s6 := s2[:2]

	s7 := s2[1:3:4]

	fmt.Println("s4 is ", s4, "  s5 is ", s5, " s6 is ", s6, "  s7 is ", s7, "s7 len is ", len(s7),
		"s7 cap is ", cap(s7))

	int_arr := make([]int, 3, 5)

	if int_arr != nil {
		fmt.Println("int_arr is ", int_arr)
	}

	// append 引用数据类型
	int_arr_add := append(int_arr, 4)

	int_arr_add_2 := append(int_arr_add, s2...)

	fmt.Println("int_arr_add is  int_ad", int_arr_add, " int_arr_add_2 is ", int_arr_add_2)

}

func Prt_init() {
	var a int = 10
	var b *int = &a

	fmt.Printf("type is %T\n", b)

	var nil_var *int

	if nil_var == nil {
		fmt.Println("nil_var is ", nil_var)
	}

	new_var := new(int)

	if new_var != nil {
		fmt.Println("new var is not nil", new_var)
	}

	var var_map map[string]int

	if var_map == nil {
		fmt.Println(" var_map is nil", var_map)
	}

	var make_var_map = make(map[string]int, 10)

	if make_var_map != nil {
		fmt.Println(" make_var_map is not nil ", make_var_map, "len is ", len(make_var_map), "cap is ")
	}

	str_map := make(map[string]map[int]string)
	println(len(str_map))

	// map结构必须 重复
	item := make(map[int]string)

	item[1] = "vale2"
	str_map["zhognwe"] = item

	str_map["zhognwe"][2] = "vale223"

	// panic
	// str_map["2123"][1] = "values2"

	fmt.Println(" str_map is ", str_map)

	for k, v := range str_map {
		fmt.Println("key is  ", k, "value is ", v)
	}

	_, exist := str_map["ro"]

	if !exist {
		fmt.Println("key ro is not exist ", exist)
	}

	map_arr := make(map[int][]int)

	map_arr[1] = []int{2, 3, 4, 5, 6, 7, 8}
	ints := []int{1, 2, 3, 4, 5, 6}
	map_arr[2] = ints

	for i := range map_arr {
		println("key is ", i)
		for i2 := range map_arr[i] {
			println("value is ", i2)
		}
	}

}

func Struct_Type() {
	type struct_obj struct {
		int
		string
		float32
	}

	obj := struct_obj{1, "string", 3.4}

	fmt.Println("obj is ", obj)

	type struct_ob2 struct {
		name, city string
		int
		float32
	}

	ob2 := struct_ob2{"name", "nan c", 2, 23.4}

	// 结构体指针类型
	var ob3 *struct_ob2 = &struct_ob2{"name", "nan c", 2, 23.4}

	fmt.Println("==== obj2 ====", ob2)
	//
	fmt.Printf("obj2 is Type %T  obj3 is Type %T", ob2, ob3)

	var struce_obj = new(struct_obj)

	struce_obj.int = 3
	struce_obj.float32 = 3.4

	fmt.Println("ptr is ", &struce_obj)
	fmt.Println("value  is ", struce_obj)

}

func Struct_person() person {
	persont := &person{"person", 10, nil}
	person_copy := persont.copy()
	if persont != person_copy {
		fmt.Println("copy is not  equal ")
	}
	// 属性组合，类似于继承
	souce := person_copy.Student

	fmt.Println("======souce ======", souce)
	return *persont
}

type person struct {
	Name    string
	Age     int
	Student *student
}

type student struct {
	souce float32
	Age   int
}

func (p person) copy() *person {
	return &person{
		p.Name,
		p.Age,
		&student{
			souce: 1.4,
			Age:   10,
		},
	}
}

func MarshalJSON() {
	person := &person{
		Age:  10,
		Name: "name",
		Student: &student{
			souce: 12.3,
			Age:   10,
		},
	}
	// struct to byte[]  无法访问私有变量
	marshal, err := json.Marshal(person)

	if err != nil {
		fmt.Println("json marshal is err", err.Error())
	}
	fmt.Println("json marshal is success  ", base64.StdEncoding.EncodeToString(marshal))
	fmt.Println("json marshal is success", string(marshal))
}

func AnonymousFun(arg ...*float64) {
	var a = 10
	// 使用变量代替函数，匿名函数
	getSqrt := func(b []*float64, a int) []*float64 {
		// 使用外部变量
		println(" getSqrt a is ", a)
		for i, v := range arg {
			sqrt := math.Sqrt(*v)
			arg[i] = &sqrt
		}
		return arg
	}

	for _, v := range getSqrt(arg, a) {
		fmt.Println("=====var==== ", *v)
	}
}

func AnonymousFun2() {
	anonymous := func(base int) func(int) int {
		return func(i int) int {
			base += i
			return base
		}
	}
	// 累计变量 base
	f := anonymous(10)
	fmt.Println("f(1)", f(1))
	fmt.Println("f(2)", f(2))
	fmt.Println("f(3)", f(3))

}

// 外部函数return 之前调用，保证函数上下文状态(对指针类型联动）
func defer_fun() {
	i := 0
	defer fmt.Println("defer 1 current status i = ", i)
	i++
	defer fmt.Println("defer 2 current status i = ", i)

	i++
	fmt.Println("current status i = ", i)

}

func panic_fun() {
	defer func() {
		// 方法中捕获panic 防止程序err导致中断
		if a := recover(); a != nil {
			// 接口err 转为 string
			// println(a.(string))
			marshal, _ := json.Marshal(a.(*student))
			fmt.Println("====== ", string(marshal))
		}
	}()

	// panic => error异常，允许在 defer recover中捕获
	panic(&student{
		souce: 12,
		Age:   13,
	})

}

func error_fun() error {

	defer func() {
		if a := recover(); a != nil {
			fmt.Println("recover error is ", a.(runtime.Error))
			// fmt.Println("recover error is ", a.(*runtime.Error))
		}
	}()

	var a, b int
	i := a / b

	fmt.Println("===== i = ", i)
	if b == 0 {
		return errors.New("integer divide by zero ")
	}
	return nil
}

func time_fun() {
	now := time.Now()
	fmt.Printf("current time:%v\n", now)

	fmt.Println(" current time ", now.Year(), int(now.Weekday()), int(now.Month()), now.Day(), now.Hour())

	fmt.Println(now.Add(time.Hour * 2).Format("15:04:05"))

	fmt.Println(now.Format("2006-01-02 15:04:05"))
}

func out_in_str() {
	fmt.Print("====== 标准输出终端")

	fmt.Printf("%v\n", 100)
	fmt.Printf("%v\n", false)
	o := struct{ name string }{"miaomiaoel"}
	fmt.Printf("%v\n", o)
	fmt.Printf("%#v\n", o)
	fmt.Printf("%T\n", o)
	fmt.Printf("100%%\n")

	fmt.Fprintf(os.Stdout, "向标准输出写入字符")

	create, err := os.Create("out.log")
	if err != nil {
		fmt.Println("创建文件失败，")
		panic(errors.Join(err))
	}

	fmt.Fprintf(create, "写入文件中 ")

	// 数据str化
	sprintf := fmt.Sprintf("数据String化 %s %t", "书银行业", true)
	fmt.Println(sprintf)

	err = fmt.Errorf("this is err %e", errors.New("-----------"))

}

func scan_keyboard() {
	var (
		name    string
		age     int
		married bool
	)
	fmt.Scan(&name, &age, &married)
	fmt.Printf("扫描结果 name:%s age:%d married:%t \n", name, age, married)
}

func opt_type_log() {
	log.Println("Println=====")

	// 触发 paninc (打印错误栈信息）
	log.Panicln("Panicln==========")

	//  终止程序os.Exit(1)
	log.Fatalln("Fatalln=============")
}

func opt_logger() {
	//  控制输出日志信息的细节，不能控制输出的顺序和格式。
	//    // 输出的日志在每一项后会有一个冒号分隔：例如2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
	//    Ldate         = 1 << iota     // 日期：2009/01/23
	//    Ltime                         // 时间：01:23:23
	//    Lmicroseconds                 // 微秒级别的时间：01:23:23.123123（用于增强Ltime位）
	//    Llongfile                     // 文件全路径名+行号： /a/b/c/d.go:23
	//    Lshortfile                    // 文件名+行号：d.go:23（会覆盖掉Llongfile）
	//    LUTC                          // 使用UTC时间
	//    LstdFlags     = Ldate | Ltime // 标准logger的初始值
	log.SetFlags(log.Lshortfile | log.Lmicroseconds | log.LstdFlags)
	log.Println("===============")
	log.Panicln("Panicln ===============")
}

func opt_uri() {
	urlStr := "postgres://user:pass@host.com:5432/path?k=v#f"

	parse, err := url.Parse(urlStr)
	if err != nil {
		log.Fatalln("string to url is fail ", err)
	}
	fmt.Println(parse.Scheme)
	fmt.Println(parse.User)
	fmt.Println(parse.User.Username())
	p, _ := parse.User.Password()
	fmt.Println(p)

	fmt.Println(parse.Host)
	host, port, _ := net.SplitHostPort(parse.Host)
	fmt.Println(host)
	fmt.Println(port)

	fmt.Println(parse.Path)
	fmt.Println(parse.Fragment)

	fmt.Println(parse.RawQuery)
	m, _ := url.ParseQuery(parse.RawQuery)
	fmt.Println(m)
	fmt.Println(m["k"][0])
}
